﻿#include"vmrun.h"
#include<malloc.h>
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
MStack s_stack;//系统调用栈
MRegister s_ax;
MVarList varlist;
int bp = 0, ep = 0;
int cp = 0;
static void printLog(char* logs)
{
	printf("<LOG>:%s\n", logs);
}
static QvmRunErr QMakeErr(int index, int level, char* info)
{
	QvmRunErr re;
	re.i = index;
	re.inf = info;
	re.level = level;
}
static void errOut(QvmRunErr err)
{
	exit(err.level);
}
static void pushStack(MValue v)
{
	if (s_stack.cp >= s_stack.size)
		errOut(QMakeErr(cp, ERRL_EXIT_BIG_MSGBOX, "SYSTEM STACK:\nProgram ran out of stack size."));
	if (!MSetValue(v.value, v.type, &s_stack.stack[s_stack.cp]))
		errOut(QMakeErr(cp, ERRL_EXIT_PRINT, "Cannot push to the stack."));
	s_stack.cp++;
	ep++;
}
static void popStack()
{
	s_stack.cp--;
	if (s_stack.cp == -1)
		errOut(QMakeErr(cp, ERRL_EXIT_BIG_MSGBOX, "SYSTEM STACK:\nProgram ran below of stack size."));
	if (!MSetValue(s_stack.stack[s_stack.cp].value, s_stack.stack[s_stack.cp].type, &s_ax))
		errOut(QMakeErr(cp, ERRL_EXIT_PRINT, "Cannot pop to the stack."));

	ep--;
}


QvmRunErr QvmRunCodes(Qvm_CodeCtl* ctl)
{
	//运行字节码
	//
	int op = -1;
	if (ctl == NULL)
		return QMakeErr(-1, ERRL_EXIT_PRINT, "Fail to load vm codes!\nMaybe fail to read files.");
	while (cp < ctl->codes.size)
	{
		op = ctl->codes.c_list[cp].op;
		if (op == VMC_SREG)
		{
			MValue v = ctl->codes.c_list[cp].lval;
			s_ax.value = v;
		}
		else if (op == VMC_PUSH)
		{
			pushStack(ctl->codes.c_list[cp].lval);
		}
		else if (op == VMC_PUSHV)
		{
			pushStack(s_ax.value);
		}
		else if (op == VMC_POP)
		{
			popStack();
		}
		else if (op == VMC_ADD)
		{
			popStack();
			MValue a = s_ax.value;
			popStack();
			MValue b = s_ax.value;
			if (a.type == VTYPE_INT && b.type == VTYPE_INT)
			{
				MSetValue(MGET_VAL_INT(a) + MGET_VAL_INT(b), VTYPE_INT, &s_ax);
			}
			else return QMakeErr(cp, ERRL_EXIT_PRINT, "No match paras to 'add'");
		}
		else if (op == VMC_SUB)
		{
			popStack();
			MValue a = s_ax.value;
			popStack();
			MValue b = s_ax.value;
			if (a.type == VTYPE_INT && b.type == VTYPE_INT)
			{
				MSetValue(MGET_VAL_INT(a) - MGET_VAL_INT(b), VTYPE_INT, &s_ax);
			}
			else return QMakeErr(cp, ERRL_EXIT_PRINT, "No match paras to 'add'");
		}
		else if (op == VMC_MUL)
		{
			popStack();
			MValue a = s_ax.value;
			popStack();
			MValue b = s_ax.value;
			if (a.type == VTYPE_INT && b.type == VTYPE_INT)
			{
				MSetValue(MGET_VAL_INT(a) * MGET_VAL_INT(b), VTYPE_INT, &s_ax);
				int a = 0;
			}
			else return QMakeErr(cp, ERRL_EXIT_PRINT, "No match paras to 'add'");
		}
		else if (op == VMC_DIV)
		{
			popStack();
			MValue a = s_ax.value;
			popStack();
			MValue b = s_ax.value;
			if (a.type == VTYPE_INT && b.type == VTYPE_INT)
			{
				MSetValue(MGET_VAL_INT(a) / MGET_VAL_INT(b), VTYPE_INT, &s_ax);
			}
			else return QMakeErr(cp, ERRL_EXIT_PRINT, "No match paras to 'add'");
		}
		else if (op == VMC_STG)
		{
			int v1 = MGET_VAL_INT(ctl->codes.c_list[cp].lval);
			if (v1 >= 0 && v1 < s_stack.size)
				s_ax.value = s_stack.stack[v1];
			else return QMakeErr(cp, ERRL_EXIT_PRINT, "Index Out Of stack.");
		}
		else if (op == VMC_VLMALL)
		{
			int r = MMallocVar(&varlist, s_stack.cp);//编译器每次malloc后都会pushv所以可以先将锁定栈地址暂定为下一个栈位
			if (r == -1)
				return QMakeErr(cp, ERRL_EXIT_MSGBOX, "Cannot malloc variable !");
			MSetValue(r, VTYPE_INT, &s_ax);
		}
		else if (op == VMC_VLL)
		{
			//先pop一个值，如果该值为err则不进行赋值，反之进行赋值
			//注意，编译器中是先值后地址，所以取出时应该是先地址后值
			popStack();
			int idx = MGET_VAL_INT(s_ax.value);
			popStack();
			MValue n = s_ax.value;
			MValue re = MGetVar(varlist, idx);
			if (n.type != VTYPE_ERR)
			{
				if (!MSetVar(&varlist, idx, n))
					return QMakeErr(cp, ERRL_EXIT_PRINT, "Cannot set variable.");
			}
			if (re.type == VTYPE_ERR)
				return QMakeErr(cp, ERRL_EXIT_MSGBOX, "Index Out Of varlist.");
			s_ax.value = re;
		}
		else if (op == VMC_VLS)
		{
			popStack();
		}
		else
			return QMakeErr(cp, ERRL_EXIT_PRINT, "fail to load command ,maybe unknow command.");
		printf("ax:%d,stack[%d]:'%d'\n", MGET_VAL_INT(s_ax.value), s_stack.cp, MGET_VAL_INT(s_stack.stack[s_stack.cp - 1]));
		cp++;
	}
	return QMakeErr(-1, -1, NULL);
}

int QvmInitMemory()
{
	s_stack = MCreateStack(1024 * 1024);
	s_ax.value = MCreateValue(1);
	varlist = MCreateVariableList(1024);
	return 1;
}
